import time
import vtkmodules.all as vtk
import platform
import numpy
import CloudEngine.Render.ITrackballSimpleCamera as ITrackballSimpleCamera
import CloudEngine.core.ArrayPlus as ArrayPlus

import pydash
from CloudEngine.Render.Selector import Selector
from CloudEngine.Render.UserInputMod import UserInputMod
from CloudEngine.Render.api.get_actor_attributes import get_actor_attributes
from CloudEngine.System.NormalSystem import NormalSystem
from CloudEngine.Render.State import StateMachine
from CloudEngine.Render.api.get_actor_list import get_actor_list
from CloudEngine.core.PubSub import EventEmitter


class Application:
    is_render_scalar_bar = False
    # 应用全局状态的存储
    state: StateMachine = None  # 状态机

    first_enter = False

    renderer = None

    event = None
    # 子模块
    UserInputMod = None

    def __init__(self, options=None):
        # 事件发布订阅
        self.event = EventEmitter()
        # 常规渲染图层
        self.renderer = vtk.vtkRenderer()
        self.renderWindow = vtk.vtkRenderWindow()
        self.renderWindowInteractor = vtk.vtkRenderWindowInteractor()
        self.camera = ITrackballSimpleCamera.ITrackballSimpleCamera()
        self.render_callback: any = None
        self.windowToImageFilter = vtk.vtkWindowToImageFilter()
        # 几何体成员队列
        self.actorList = ArrayPlus.ArrayPlus([])
        # 基本图元成员队列
        self.graphicActorList = ArrayPlus.ArrayPlus([])
        # 文字成员队列
        self.labelActorList = ArrayPlus.ArrayPlus([])

        self.state = StateMachine()
        self.queue = None
        self.other_process = None
        self.result_queue = None
        self.selector = Selector(self)
        self.init_canvas()
        self.d_render = pydash.debounce(self.render_at_once, 50)
        # 使用vtkImageExport将图像数据导出为字节
        self.imageExport = vtk.vtkImageExport()
        self.imageExport.SetInputConnection(self.windowToImageFilter.GetOutputPort())
        self.manager = None
        self.SystemNormal = NormalSystem(self)
        # 子模块初始化
        self.UserInputMod = UserInputMod(self, self.selector)

    def init_canvas(self):
        self.renderWindow.SetWindowName("CloudRender")
        self.renderWindow.AddRenderer(self.renderer)
        self.renderWindowInteractor.SetRenderWindow(self.renderWindow)
        self.renderWindowInteractor.SetPicker(self.selector.cellPicker)
        self.renderWindowInteractor.SetInteractorStyle(self.camera)
        self.renderWindow.SetOffScreenRendering(1)  # 启用离屏渲染
        self.renderWindow.SetSize(1920, 1080)
        self.windowToImageFilter.SetInput(self.renderWindow)
        self.windowToImageFilter.SetScale(1)  # 图像缩放
        self.windowToImageFilter.SetInputBufferTypeToRGB()  # 设置图像格式
        self.windowToImageFilter.ReadFrontBufferOff()

    def run(self):
        self.renderer.SetBackground(233 / 255, 236 / 255, 239 / 255)  # 设置背景颜色
        self.renderWindow.AddObserver("RenderEvent", self.on_render)
        # 初始化并启动渲染和交互
        self.renderWindow.Render()

    def export_image(self):
        self.windowToImageFilter.Modified()
        self.windowToImageFilter.Update()
        # 准备一个numpy数组来存储图像字节
        width, height, _ = self.windowToImageFilter.GetOutput().GetDimensions()
        num_components = (
            self.windowToImageFilter.GetOutput().GetNumberOfScalarComponents()
        )
        image_array = numpy.zeros((height, width, num_components), dtype=numpy.uint8)
        # 将图像数据导出到numpy数组
        self.imageExport.Export(image_array)
        if self.queue is not None:
            self.queue.put(image_array)

    def render(self):
        # a = time.time()
        self.renderWindow.Render()
        # b = time.time()
        self.export_image()
        # c = time.time()
        # print("Rendering took", (b - a) * 1000)
        # print("image took", (c - b) * 1000)

    def render_at_once(self):
        self.render()

    def on_render(self, caller, event):
        self.update()
        if self.render_callback is not None:
            self.render_callback()

    def right_button_press(self, x, y):
        self.UserInputMod.right_button_press(x, self.renderWindow.GetSize()[1] - y)

    def right_button_release(self, x, y):
        print("[Application] 右键 ↑", x, y)

    def left_button_press(self, x, y, ctrl=False, shift=False):
        # print("[Application] 左键 ↓", x, y)
        if shift:
            self.camera.TriggerPan(x, y)
        else:
            self.camera.TriggerRotate(x, y)

    def left_button_release(self, x, y):
        # print("[Application] 左键 ↑", x, y)
        self.camera.TriggerEndRotate(x, y)
        self.camera.TriggerEndPan(x, y)

    def mouse_wheel(self, dx, dy):
        # print("[Application] 滚轮 ", dx, dy)
        self.camera.TriggerZoomDelta(dy)

    def mouse_move(self, x, y, ctrl=False, shift=False):
        self.camera.TriggerMouseMove(x, y)

    def accept_event(self):
        return self.camera.CanAcceptMouseMove()

    def get_state(self) -> int:
        return self.camera.GetState()

    def add(self, actor):
        if hasattr(actor, "type") and actor.type == "VT_ACTOR":
            self.renderer.AddActor(actor.instance)
            self.selector.AddToTargetList(actor)
            self.selector.AddToPointTargetList(actor)
            if actor.outlines is not None:
                self.renderer.AddActor(actor.outlines.instance)
                self.selector.setLineTargetList(actor.outlines)
            if actor.vertexesActor is not None:
                self.renderer.AddActor(actor.vertexesActor.instance)
            # 推入到数组中
            self.actorList.push(actor)
        elif hasattr(actor, "type") and actor.type == "LABEL":
            self.renderer.AddActor(actor.instance)
        elif hasattr(actor, "type") and actor.type == "GRAPHIC_ACTOR":
            self.renderer.AddActor(actor.instance)
        else:
            self.renderer.AddActor(actor.instance)
        # 是否第一次进入
        if self.first_enter:
            self.first_enter = False
        self.renderer.ResetCamera()
        self.render()

    def remove(self, actor):
        if actor is not None:
            self.renderer.RemoveActor(actor.instance)
        if hasattr(actor, "type") and actor.type == "GRAPHIC_ACTOR":
            self.graphicActorList.remove(actor)
        if hasattr(actor, "type") and actor.type == "VT_ACTOR":
            self.actorList.remove(actor)

    def remove_all(self):
        self.renderer.RemoveAllViewProps()
        self.actorList.empty()
        self.graphicActorList.empty()
        self.labelActorList.empty()

    def update(self):
        self.SystemNormal.update()

    def render_with_desktop(self):
        self.renderer.ResetCamera()
        self.renderWindow.SetOffScreenRendering(False)
        self.renderWindowInteractor.Start()

    def reset_camera(self):
        self.renderer.ResetCamera()
        # 解决某些时候z-fighting的问题
        self.renderer.GetActiveCamera().SetClippingRange(1, 10000)

    def get_actors_list(self):
        return get_actor_list(self)

    def get_actor_attributes(self, actor_id):
        return get_actor_attributes(self, actor_id)

    def resize(self, width, height):
        self.renderWindow.SetSize(width, height)

    def add_scalar_bar(self, actor):
        self.renderer.AddActor2D(actor)

    def remove_scalar_bar(self, actor):
        self.renderer.RemoveActor2D(actor)

    def save_image(self):
        self.windowToImageFilter.Modified()
        self.windowToImageFilter.Update()
        png_writer = vtk.vtkPNGWriter()  # 也可以选择其他格式如 JPEGWriter
        png_writer.SetFileName("screenshot.png")
        png_writer.SetInputConnection(self.windowToImageFilter.GetOutputPort())
        png_writer.Write()
